package org.example.infrastructure;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.example.config.SecurityTokenConfig;
import org.example.constant.LoginTypeConstant;
import org.example.domain.model.repository.LoginTypeStrategeRepository;
import org.example.domain.system.constant.SecurityConstant;
import org.example.domain.system.model.LoginUser;
import org.example.domain.system.model.UserAccount;
import org.example.domain.system.model.req.UserLoginReq;
import org.example.infrastructure.repository.RedisService;
import org.example.utils.DateUtils;
import org.example.utils.JwtUtils;
import org.example.utils.SnowFlake;
import org.example.utils.StringUtils;
import org.example.web.exception.ServerException;
import org.example.web.result.BaseErrorCode;
import org.springframework.stereotype.Component;

import java.time.LocalDate;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;


@Component(LoginTypeConstant.PC_LOGIN_TYPE)
@Slf4j
@RequiredArgsConstructor
public class PCLoginTypeStrategeInfrastructure implements LoginTypeStrategeRepository {
    private final SecurityTokenConfig securityConfig;
    private final RedisService redisService;

    @Override
    public UserAccount loginVerify(UserLoginReq userLoginReq, UserAccount userAccount) {

        if (Boolean.TRUE.equals(userAccount.getDeleteIdentity())) {
            log.error("账号为=>{} 已被删除!", userAccount.getUserName());
            throw new ServerException("对不起，您的账号：" + userAccount.getUserName() + " 已被删除");
        }
        if (Boolean.TRUE.equals(userAccount.getStatus())) {
            log.error("账号为=>{} 已停用!", userAccount.getUserName());
            throw new ServerException("对不起，您的账号：" + userAccount.getUserName() + " 已停用");
        }
        LocalDate accountExpirationDate = DateUtils.dateToLocalDate(userAccount.getExpirationDate());
        // 获取前一天的日期
        LocalDate previousDay = LocalDate.now().minusDays(1);
        if (previousDay.isAfter(accountExpirationDate)) {
            // 账号已过期，采取相应的措施
            log.error("账号为=>{} 已过期!", userAccount.getUserName());
            throw new ServerException("对不起，您的账号：" + userAccount.getUserName() + " 已过期");
        }

        if (!userAccount.matchesPassword(userLoginReq.getPassword())) {
            throw new ServerException(BaseErrorCode.PASSWORD_VERIFY_ERROR);
        }

        if (!securityConfig.getSoloLogin()) {
            // 如果用户不允许多终端同时登录，清除缓存信息，清除上一个用户的缓存
        }


        return userAccount;
    }

    @Override
    public Map<String, Object> authentication(LoginUser loginUser) {
        SnowFlake snowFlake = new SnowFlake();
        long tokenKey = snowFlake.nextId();
        String userName = loginUser.getUserName();
        Long userId = loginUser.getUserId();
        HashMap<String, Object> claimsMap = new HashMap<>(4);
        loginUser.setTokenKey(tokenKey);
        refreshToken(loginUser);
        // Jwt存储信息
        claimsMap.put(SecurityConstant.SECURITY_TOKEN_KEY, loginUser.getTokenKey());
        claimsMap.put(SecurityConstant.SECURITY_USER_ID, userId);
        claimsMap.put(SecurityConstant.SECURITY_USER_NAME, userName);
        claimsMap.put(SecurityConstant.SECURITY_LOGIN_USER, loginUser);
        claimsMap.put(SecurityConstant.SECURITY_LOGIN_TYPE, LoginTypeConstant.PC_LOGIN_TYPE);
        // 接口返回信息
        HashMap<String, Object> rspMap = new HashMap<>(2);
        rspMap.put(SecurityConstant.SECURITY_TOKEN_KEY, JwtUtils.createToken(claimsMap));
        rspMap.put(SecurityConstant.SECURITY_EXPIRE_TIME, securityConfig.getExpireTime());
        return rspMap;
    }

    @Override
    public LoginUser getLoginUser(String token) {
        LoginUser loginUser = JwtUtils.getLoginUser(token);
        if (!hasToken(loginUser.getTokenKey())) {
            throw new ServerException(BaseErrorCode.IDEMPOTENT_TOKEN_VERIFY_ERROR);
        }
        return JwtUtils.getLoginUser(token);
    }

    @Override
    public void verifyLoginUserExpire(LoginUser loginUser) {
        refreshToken(loginUser);
    }


    @Override
    public void logoutByTokenCache(String token) {
        if (StringUtils.isNotEmpty(token)) {
            LoginUser userTokenKey = JwtUtils.getLoginUser(token);
            redisService.deleteObject(userTokenKey.getTokenKey());
        }
    }

    @Override
    public Boolean hasToken(String userTokenKey) {
        return redisService.hasKey(userTokenKey);
    }


    /**
     * 刷新令牌有效期
     */
    public void refreshToken(LoginUser loginUser) {
        // 根据token将loginUser缓存
        String userTokenKey = loginUser.getTokenKey();
        redisService.setCacheObject(userTokenKey, loginUser, securityConfig.getExpireTime(), TimeUnit.MINUTES);
    }


}
